/*
 * This file is part of quickReminder, a software for gamers
 *
 * Copyright (C) 2006-2008 Lucas Romero
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Threading;
using System.Management;
using System.Diagnostics;
//using GA_ScreenScraper;
using LucasCode;
using LucasCode.Win32;
using LucasCode.Tools;
using System.IO;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text.RegularExpressions;
using ManagedWinapi.Accessibility;
using ManagedWinapi.Windows;
using System.Collections;
using DbMon.NET;
using HtmlAgilityPack;
using UserNotifier;

namespace ESLReminder
{
    public enum ConsoleEventItemType
    {
        StatusScreenshotTaken,
        RestartCommandIssued,
        DemoStarted,
        DemoStopped,
        PlayerConnected,
        PlayerSwitchedTeam,
        None
    }
    public class ConsoleEventItem
    {
        public ConsoleEventItemType EventType;
        public string EventText;
        public DateTime EventTime;
        public ConsoleEventItem(DateTime EventTime, ConsoleEventItemType EventType, string EventText)
        {
            this.EventTime = EventTime;
            this.EventText = EventText;
            this.EventType = EventType;
        }
    }
    
    public class ConsoleEventItemCollection : CollectionBase
    {
        public int Add(ConsoleEventItem item)
        {
            //lock (List)
                return List.Add(item);
        }
        public void Insert(int index, ConsoleEventItem item)
        {
            //lock (List)
                List.Insert(index, item);
        }
        public void Remove(ConsoleEventItem item)
        {
            //lock (List)
                List.Remove(item);
        }
        public bool Contains(ConsoleEventItem item)
        {
            //lock (List)
                return List.Contains(item);
        }
        public int IndexOf(ConsoleEventItem item)
        {
            //lock (List)
                return List.IndexOf(item);
        }
        public void CopyTo(ConsoleEventItem[] array, int index)
        {
            //lock (List)
                List.CopyTo(array, index);
        }
        public ConsoleEventItem this[int index]
        {
            get { return (ConsoleEventItem)List[index]; }
            set { List[index] = value; }
        }
    } 
    /*
    public class UpdateEventArgs : EventArgs
    {
        public UpdateEventArgs(UpdateStatus Status, int Progress, string ErrorMessage)
        {
            m_UpdateStatus = Status;
            m_Progress = Progress;
            m_ErrorMessage = ErrorMessage;
        }
        private int m_Progress = 0;
        private UpdateStatus m_UpdateStatus = UpdateStatus.Idle;
        private string m_ErrorMessage = string.Empty;
        #region Public get's
        public string ErrorMessage
        {
            get
            {
                return m_ErrorMessage;
            }
        }

        public UpdateStatus Status
        {
            get
            {
                return m_UpdateStatus;
            }
        }
        public int Progress
        {
            get
            {
                return m_Progress;
            }
        }
        #endregion
    }*/
    public class ESLReminder
    {
        #region Events
        public delegate void GameStartedEventHandler(ESLReminder sender, bool LeagueMatch);
        public delegate void GameExitedEventHandler(ESLReminder sender);
        public delegate void FilesCollectedEventHandler(ESLReminder sender, StringCollection FileList, string MatchURL,ConsoleEventItemCollection events);
        public delegate void StatusTextChangedEventHandler(ESLReminder sender, String text);
        public delegate void OnExceptionEventHandler(ESLReminder sender, Exception ex);
        public event GameStartedEventHandler GameStarted;
        public event GameExitedEventHandler GameExited;
        public event FilesCollectedEventHandler FilesCollected;
        public event StatusTextChangedEventHandler StatusTextChanged;
        public event OnExceptionEventHandler OnException;
        #endregion

        Timer MainTimer = null;
        Timer DemoTimer = null;

        Process GameProcess = null;
        Process AequitasProcess = null;
        bool DemoWritten = false;
        //public OSDWarnModule osd = new OSDWarnModule(10);

        public WarnModuleCollection WarnModules = new WarnModuleCollection();


        //ArrayList FileSystemWatchers = new ArrayList();
        FileSystemWatcher AequitasWatcher;
        FileSystemWatcher CstrikeWatcher;
        FileSystemWatcher ReplayWatcher;
        FileSystemWatcher ScreenshotWatcher;
        StringCollection FileList = new StringCollection();
        ConsoleEventItemCollection ConsoleEvents = new ConsoleEventItemCollection();

        Process[] RunningProcesses;

        private void GameProcessFound()
        {
            Trace.WriteLine("Game Process found!");
                m_Gamename = GameProcess.ProcessName;
                //deactivate MainTimer
                MainTimer.Change(Timeout.Infinite, Timeout.Infinite);

                FileList.Clear();
                ConsoleEvents.Clear();
                
                try
                {
                    Trace.WriteLine("Process: " + GameProcess.MainModule.FileName);
                }catch{}
                GameProcess.Exited += new EventHandler(GameProcess_Exited);
                GameProcess.EnableRaisingEvents = true;
                if(SetPrioGame)
                    GameProcess.PriorityClass = ProcessPriorityClass.AboveNormal;
                if (SetAffinityGame && ProcessAffinityGame < System.Environment.ProcessorCount)
                {
                    GameProcess.ProcessorAffinity = new IntPtr(1 << ProcessAffinityGame);
                }
                
                

                

                bool MatchOpen=true;
                try
                {
                    if (StatusTextChanged != null)
                        StatusTextChanged(this, "Checking for open match...");
                    if(!WarnAlways)
                        Trace.WriteLine("Checking for open match...");
                    else
                        Trace.WriteLine("WarnAlways is on.");
                    //set open match always to true when "WarnAlways" is enabled
                    MatchOpen = WarnAlways ? true : ESLHelpers.isMatchInReach(OffsetBefore, OffsetAfter, LoginCookie, DebugEnabled,MatchFilter);
                }
                catch (System.Exception e)
                {
                    MatchOpen = true;
                	Trace.WriteLine(e.Message);
                    Trace.WriteLine(e.StackTrace);
                    //if (OnException != null)
                        //OnException(this, e);
                }

                if (MatchOpen)
                {
                    if (!WarnAlways)
                        Trace.WriteLine("Open match found!");
                    if (StatusTextChanged != null)
                        StatusTextChanged(this, "Open match found");

                    OSDWarnModule osd = WarnModules.getOSDWarnModule();
                    if (osd != null)
                        osd.GameProcess = GameProcess;

                    if (!ESLHelpers.isAequitasMonitoring())
                    {
                        Trace.WriteLine("No monitoring aequitas found!");
                        WarnModules.Warn(WarnEvents.NoAequitas);
                        if (StatusTextChanged != null)
                            StatusTextChanged(this, "No monitoring aequitas found!");
                    }
                    else
                    {
                        Trace.WriteLine("aequitas is monitoring");
                        if (WarnOnNoStatus)
                            WarnModules.Warn(WarnEvents.TakeStatus);
                        if (StatusTextChanged != null)
                            StatusTextChanged(this, "aequitas running!");

                        //initialize aeq-process
                        RunningProcesses = Process.GetProcessesByName("aequitas");
                        if (RunningProcesses.Length > 0)
                            AequitasProcess = RunningProcesses[0];
                        
                        Trace.WriteLine("--- " + AequitasProcess.MainWindowTitle + " /// " + AequitasProcess.MainWindowHandle.ToString() + "---");
                        m_MatchLink = ESLHelpers.getMatchLink();

                        //initialize aeqwatcher
                        if (AequitasProcess != null)
                        {
                            Trace.WriteLine("Setting up aequitaswatcher");
                            AequitasProcess.Exited += new EventHandler(AequitasProcess_Exited);
                            AequitasProcess.EnableRaisingEvents = true;
                            if (SetAffinityAequitas && ProcessAffinityAequitas < System.Environment.ProcessorCount)
                            {
                                try
                                {
                                	AequitasProcess.ProcessorAffinity = new IntPtr(1 << ProcessAffinityAequitas);
                                }
                                catch (System.Exception e)
                                {
                                    Trace.WriteLine("ERROR: could not set Processor affinity: " + e.Message);
                                }
                            }
                            try
                            {
                                AequitasWatcher = new FileSystemWatcher(Path.GetDirectoryName(AequitasProcess.MainModule.FileName) + Path.DirectorySeparatorChar + "archive");
                            }
                            catch { }
                            if (AequitasWatcher != null)
                            {
                                AequitasWatcher.IncludeSubdirectories = true;
                                AequitasWatcher.InternalBufferSize = 4 * AequitasWatcher.InternalBufferSize;
                                AequitasWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size;
                                AequitasWatcher.Created += new FileSystemEventHandler(AequitasWatcher_Changed);
                                AequitasWatcher.Changed += new FileSystemEventHandler(AequitasWatcher_Changed);
                                AequitasWatcher.EnableRaisingEvents = true;
                            }
                            Trace.WriteLine("Aequitas watcher set up " + AequitasWatcher != null ? "successful." : "failed!");
                        }
                        if (StatusTextChanged != null)
                            StatusTextChanged(this, "Monitoring match...");
                    }
                    string mod = string.Empty;
                    try
                    {
                        Trace.WriteLine("Using WMI to get param info");
                        //Use WMI to get the commandline-parameters hl/hl2 was started with
                        ManagementObjectSearcher query = new ManagementObjectSearcher(String.Format("SELECT * FROM Win32_Process WHERE Name='{0}'", Path.GetFileName(GameProcess.MainModule.FileName)));
                        ManagementObjectCollection queryCollection = query.Get();
                        Debug.WriteLine(queryCollection.Count.ToString() + " instances found!");
                        
                        foreach (ManagementObject mo in queryCollection)
                        {
                            //Console.WriteLine("PID [ {0} ] started '{1}' With commandline - '{2}'", mo["ProcessID"].ToString(), mo["CreationDate"].ToString(), mo["CommandLine"].ToString());
                            //if(mo["ProcessID"].ToString() == GameProcess.Id.ToString())
                            Trace.WriteLine(String.Format("PID [ {0} ] started '{1}' With commandline - '{2}'", mo["ProcessID"].ToString(), mo["CreationDate"].ToString(), mo["CommandLine"].ToString()));
                            Match m = Regex.Match(mo["CommandLine"].ToString(), @"-game (\S+)");
                            if (m.Success)
                            {
                                mod = m.Groups[1].Value;
                            }
                        }
                    }
                    catch (System.Exception e)
                    {
                    	Trace.WriteLine("Error while parsing commanline arguments: " + e.Message);
                        Trace.WriteLine("Using fallback routine");
                        mod = getModFromDir(Path.GetDirectoryName(GameProcess.MainModule.FileName));
                    }
                    m_Mod = mod;
                    //initialize cs-watcher
                    if (mod != String.Empty)
                    {
                        Trace.WriteLine("Recognized mod: " + mod);

                        try
                        {
                            string GamePath = Path.Combine(Path.GetDirectoryName(GameProcess.MainModule.FileName), mod);
                            ReplayWatcher = new FileSystemWatcher(GamePath, "*.dem");
                            ReplayWatcher.Changed += new FileSystemEventHandler(ReplayWatcher_Changed);
                            ReplayWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size;
                            ReplayWatcher.IncludeSubdirectories = true;
                            ReplayWatcher.EnableRaisingEvents = true;
                            if (WarnOnNoDemo)
                                DemoTimer.Change(0, m_DemoTimerInterval);
                            switch (m_Gamename)
                            {
                                case "hl2":
                                    ScreenshotWatcher = new FileSystemWatcher(Path.Combine(GamePath, "screenshots"), "*.jpg");
                                    break;
                                case "hl":
                                    ScreenshotWatcher = new FileSystemWatcher(GamePath, "*.bmp");
                                    break;
                            }
                            if (ScreenshotWatcher != null)
                            {
                                ScreenshotWatcher.Created += new FileSystemEventHandler(ScreenshotWatcher_Created);
                                ScreenshotWatcher.EnableRaisingEvents = true;
                                ScreenshotWatcher.NotifyFilter = NotifyFilters.FileName;
                            }
                            else
                            {
                                Trace.WriteLine("Could not create ScreenshotWatcher!");
                            }
                        }
                        catch (Exception ex)
                        {
                            Trace.WriteLine("ERROR: could not initialize replay/screenshot-watcher: " + ex.Message);
                        }
                        /*if (CstrikeWatcher != null)
                        {
                            CstrikeWatcher.IncludeSubdirectories = true;
                            CstrikeWatcher.InternalBufferSize = 8 * CstrikeWatcher.InternalBufferSize;
                            CstrikeWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size | NotifyFilters.FileName;
                            CstrikeWatcher.Created += new FileSystemEventHandler(CstrikeWatcher_Changed);
                            CstrikeWatcher.Changed += new FileSystemEventHandler(CstrikeWatcher_Changed);

                            CstrikeWatcher.EnableRaisingEvents = true;

                            //start demo-timer
                            
                        }*/
                    }
                    try
                    {
                        if (!m_DisableDebugMonitor)
                        {
                            Trace.WriteLine("Starting DebugMonitor");
                            DebugMonitor.Start();
                            Trace.WriteLine("DebugMonitor started");
                        }
                    }
                    catch (Exception ex)
                    {
                        Trace.Write(ex.Message + " @ " + ex.StackTrace);
                    }
                    try
                    {
                        Trace.WriteLine("Getting free disk space");
                        ulong a, b, c;
                        Kernel32.GetDiskFreeSpaceEx(Path.GetPathRoot(GameProcess.MainModule.FileName), out a, out b, out c);
                        Trace.WriteLine("Logical Disk FreeSpace = " + a + " bytes");
                        if (a < FreeDiskspaceWarnThreshold * 1024 * 1024)
                            WarnModules.Warn(WarnEvents.LowDiskspace, 20000);
                    }
                    catch (System.Exception e)
                    {
                        Trace.WriteLine("ERROR reading diskspace: " + e.Message);
                    }
                    Trace.WriteLine("Reminder functions and hooks set up, monitoring game.");
                }
                else
                {
                    Trace.WriteLine("No open match, sleeping...");
                    WarnModules.Ignore();
                    StatusTextChanged(this, "Waiting for HL/HL2 to exit");
                    if (ParseConsoleAlways && !m_DisableDebugMonitor)
                    {
                        try
                        {
                            Trace.WriteLine("Starting DebugMonitor");
                            DebugMonitor.Start();
                            Trace.WriteLine("DebugMonitor started");
                        }
                        catch (Exception ex)
                        {
                            Trace.Write(ex.Message + " @ " + ex.StackTrace);
                        }
                    }
                }

                //Debug.WriteLine("Game found!");
                Trace.WriteLine("Open match: " + MatchOpen.ToString());
                //fire event to MainForm
                if (GameStarted != null)
                    GameStarted(this, MatchOpen);
        }
        private string getModFromDir(string path)
        {
            string mod=string.Empty;
            DateTime LastWriteAccess = DateTime.MinValue;
            DirectoryInfo[] dirs = new DirectoryInfo(path).GetDirectories();
            foreach (DirectoryInfo d in dirs)
            {
                FileInfo icon = new FileInfo(Path.Combine(d.FullName, "game.ico"));
                if (icon.Exists)
                {
                    if (icon.LastWriteTime > LastWriteAccess)
                    {
                        mod = d.Name;
                        LastWriteAccess = icon.LastWriteTime;
                    }
                }
            }
            return mod;
        }
        
public double GetHDDFreeSpace(string drive)
{
    //check to see if the user provided a drive letter
    //if not default it to "C"
    /*if (drive == "" || drive == null)
    {
        drive = "C";
    }*/
    //create our ManagementObject, passing it the drive letter to the
    //DevideID using WQL
    ManagementObject disk = new ManagementObject("Win32_LogicalDisk.DeviceID=\"" + drive);
    //bind our management object
    disk.Get();
    //return the free space amount
    return Convert.ToDouble(disk["FreeSpace"]);
} 

        void ScreenshotWatcher_Created(object sender, FileSystemEventArgs e)
        {
            if (!FileList.Contains(e.FullPath))
                lock (FileList)
                    FileList.Add(e.FullPath);
        }

        void ReplayWatcher_Changed(object sender, FileSystemEventArgs e)
        {
            DemoWritten = true;
            WarnModules.UnWarn(WarnEvents.NoReplay);
            Debug.WriteLine(e.FullPath + " changed");
            if (!FileList.Contains(e.FullPath))
                lock (FileList)
                    FileList.Add(e.FullPath);
            if (OverwriteProtectionEnabled)
            {
                try
                {
                    string newname = Path.Combine(Path.GetDirectoryName(e.FullPath),Path.GetFileNameWithoutExtension(e.FullPath) + "_" + DateTime.Now.ToString().Replace(":", "-").Replace(" ", "_") + ".dem");
                    File.Move(e.FullPath, newname);
                    lock (FileList)
                    {
                        FileList.Remove(e.FullPath);
                        FileList.Add(newname);
                        Debug.WriteLine("Renamed " + e.FullPath + ".");
                    }
                    
                }
                catch (IOException) { }
            }
        }

        void AequitasWatcher_Changed(object sender, FileSystemEventArgs e)
        {
            if (!FileList.Contains(e.FullPath))
                lock (FileList)
                    FileList.Add(e.FullPath);
        }

        private void MainTimerTick(object dummy)
        {
            //Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.BelowNormal;
            //Debug.WriteLine("MainTick");
            
            RunningProcesses = Process.GetProcessesByName("hl");
            if(RunningProcesses.Length > 0)
            {
                GameProcess = RunningProcesses[0];
                m_GameVersion = 1;
            }
            else
            {
                RunningProcesses = Process.GetProcessesByName("hl2");
                if (RunningProcesses.Length > 0)
                {
                    GameProcess = RunningProcesses[0];
                    m_GameVersion = 2;
                }
            }
            if (isRunning)
                GameProcessFound();
        }

        void AequitasProcess_Exited(object sender, EventArgs e)
        {
            if (AequitasWatcher != null)
            {
                AequitasWatcher.EnableRaisingEvents = false;
                AequitasWatcher.Dispose();
            }
            if(GameProcess != null && !GameProcess.HasExited)
            {
                WarnModules.Warn(WarnEvents.NoAequitas);
            }
        }



        void GameProcess_Exited(object sender, EventArgs e)
        {
            Trace.WriteLine("Game process died!");
            
            GameProcess = null;
            if (StatusTextChanged != null)
            {
                Trace.WriteLine("Firing StatusTextChanged event (GameTerminated)");
                StatusTextChanged(this, "Game terminated...");
            }
            
            if (CstrikeWatcher != null)
            {
                CstrikeWatcher.EnableRaisingEvents = false;
                CstrikeWatcher.Dispose();
            }

            
            //Stop demo-timer
            DemoTimer.Change(Timeout.Infinite, Timeout.Infinite);


            if (StatusTextChanged != null)
            {
                Trace.WriteLine("Firing StatusTextChanged event (WaitingForAequitas)");
                StatusTextChanged(this, "Waiting for aequitas to finish monitoring...");
            }
            /*if (AutoStopMonitoring && AequitasProcess != null && !AequitasProcess.HasExited)
            {
                try
                {
                    ManagedWinapi.Windows.SystemWindow aeqwin = new SystemWindow(User32.FindWindowEx(IntPtr.Zero, IntPtr.Zero, "ESL Aequitas - Steam Version *BETA*", "ThunderRT6FormDC"));
                    foreach (SystemWindow w in aeqwin.AllDescendantWindows)
                    {

                        if (w.Title == "ESL Aequitas - Steam Version *BETA*")
                        {
                            foreach (SystemWindow w2 in w.AllChildWindows)
                            {
                                Debug.WriteLine("found '" + w2.Title + "' (title '" + w2.ClassName + "')");
                                if (w2.Title == "End Monitoring")
                                {
                                    Debug.WriteLine("FOUND AEQUITAS-BUTTON!");
                                    SystemAccessibleObject stopmon = SystemAccessibleObject.FromWindow(w2, AccessibleObjectID.OBJID_WINDOW);
                                    foreach (SystemAccessibleObject o in stopmon.Children)
                                        if (o.Name == "End Monitoring")
                                        {
                                            o.DoDefaultAction();
                                            o.DoDefaultAction();
                                            break;
                                        }
                                    break;
                                }
                            }
                            break;
                        }
                    }
                }catch{}
            }*/
            try
            {
                //FIXME check if aequitas window is open
                if (AequitasWatcher != null && AequitasProcess != null)
                {
                    Trace.WriteLine("Waiting for aequitas to finish monitoring");
                    AequitasWatcher.WaitForChanged(WatcherChangeTypes.Created | WatcherChangeTypes.Changed, 60000);
                    Trace.WriteLine("Finished waiting for aequitas");
                }
            }catch{}
            Trace.WriteLine("building file list for upload");
            StringCollection files = new StringCollection();
            StringBuilder s = new StringBuilder();
            foreach (string file in FileList)
            {
                if (File.Exists(file))
                {
                    files.Add(file);
                    s.Append(file + Environment.NewLine);
                }
            }
            Trace.WriteLine("Finished building file list");
            //
            //Start main-timer
            MainTimer.Change(0, m_MainTimerInterval);


            if (StatusTextChanged != null)
            {
                Trace.WriteLine("Firing StatusTextChanged event (waiting for gamelaunch)");
                StatusTextChanged(this, "Waiting for gamelaunch...");
            }
            //fire events
            if (GameExited != null)
            {
                Trace.WriteLine("Firing GameExited event");
                GameExited(this);
            }

            if (FilesCollected != null)
            {
                Trace.WriteLine("Firing FilesCollected event");
                FilesCollected(this, files, m_MatchLink, ConsoleEvents);
            }
            try
            {
                if (DebugMonitor.isRunning)
                {
                    Trace.WriteLine("Stopping Debugmonitor");
                    DebugMonitor.Stop();
                    Trace.WriteLine("Debugmonitor stopped");
                }
            }
            catch (Exception ex)
            {
                Trace.Write(ex.Message + " @ " + ex.StackTrace);
            }
            //Stop notifier
            Trace.WriteLine("Stopping WarnModules");
            WarnModules.Stop();
            Trace.WriteLine("WarnModules stopped");
            WarnModules.UnIgnore();
            //Debug.WriteLine("Files created: " + s.ToString());
            
        }
        public void IgnoreWarnings()
        {
            
            /*if (CstrikeWatcher != null)
            {
                CstrikeWatcher.EnableRaisingEvents = false;
                CstrikeWatcher.Dispose();
            }*/
            //Stop notifier
            WarnModules.Ignore();
            //Stop demo-timer
            DemoTimer.Change(Timeout.Infinite, Timeout.Infinite);
            
            FileList.Clear();
            if (StatusTextChanged != null)
                StatusTextChanged(this, "Ignoring warning until HL/HL2 exits...");
            if (!ParseConsoleAlways)
            {
                try
                {
                    DebugMonitor.Stop();
                }
                catch (Exception ex)
                {
                    Trace.Write(ex.Message + " @ " + ex.StackTrace);
                }
            }
            
        }

        private void DemoTimerTick(object dummy)
        {
            Debug.WriteLine("DemoTick");
            //TODO
            if (!DemoWritten && WarnOnNoDemo)
            {
                Debug.WriteLine("No Demo recording!");
                //TODO: Warn User
                //osd.AddWarning("No Demo recording!");
                WarnModules.Warn(WarnEvents.NoReplay);
            }
            DemoWritten = false;
        }

        public ESLReminder()
        {
            //Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.BelowNormal;
            WarnModules.TryLoad("default.qwm");
            MainTimer = new Timer(new TimerCallback(MainTimerTick));
            DemoTimer = new Timer(new TimerCallback(DemoTimerTick));

            //Start main-timer
            MainTimer.Change(0, m_MainTimerInterval);
            /*hl = new ProcessInfo("hl.exe");
            hl2 = new ProcessInfo("hl.exe");
            hl.Started += new ProcessInfo.StartedEventHandler(hl_Started);
            hl2.Started += new ProcessInfo.StartedEventHandler(hl2_Started);*/
            if(DebugEnabled)
            {
                
                //Debug.Listeners.Add(new ConsoleTraceListener());
                if (File.Exists("debug.xml"))
                    File.Delete("debug.xml");
                Trace.Listeners.Add(new XmlWriterTraceListener("debug.xml"));

                if (File.Exists("debug.txt"))
                    File.Delete("debug.txt");
                Trace.Listeners.Add(new TextWriterTraceListener("debug.txt"));
                //Debug.Listeners.Add(new DelimitedListTraceListener("debug.txt"));
                Trace.AutoFlush = true;
            }
            DebugMonitor.OnOutputDebugString += new OnOutputDebugStringHandler(DebugMonitor_OnOutputDebugString);
        }

        void hl2_Started(object sender, EventArgs e)
        {
            MainTimerTick(null);
        }

        void hl_Started(object sender, EventArgs e)
        {
            MainTimerTick(null);
        }

        public class DebugMonitorData
        {
            public DebugMonitorData(int pid, string text)
            {
                this.Time = DateTime.Now;
                this.Text = text;
                this.PID = pid;
            }
            public string Text;
            public int PID;
            public DateTime Time;
        };

        public void ProcessDebugEvent(object debugdata)
        {
            Thread.CurrentThread.Name = "ProgressDebugEvent";
            ConsoleEventItem d = debugdata as ConsoleEventItem;
            
            d.EventText = d.EventText.Trim();

            if (d.EventText.StartsWith("hostname: "))
            {
                d.EventType = ConsoleEventItemType.StatusScreenshotTaken;
                WarnModules.UnWarn(WarnEvents.TakeStatus);
            }
            else if (d.EventText.StartsWith("The game will restart in "))
            {
                d.EventType = ConsoleEventItemType.RestartCommandIssued;
            }
            else if (d.EventText.StartsWith("recording to "))
            {
                d.EventType = ConsoleEventItemType.DemoStarted;
            }
            else if (d.EventText.StartsWith("Completed demo"))
            {
                d.EventType = ConsoleEventItemType.DemoStopped;
            }
            else if (d.EventText.EndsWith(" is joining the Counter-Terrorist force") || d.EventText.EndsWith(" is joining the Terrorist force"))
            {
                if (WarnOnTeamchange)
                    WarnModules.Warn(WarnEvents.RestartReplay, 10000);
                d.EventType = ConsoleEventItemType.PlayerSwitchedTeam;
            }
            else if (d.EventText.EndsWith(" connected") && d.EventText.StartsWith("["))
            {
                d.EventType = ConsoleEventItemType.PlayerConnected;
            }
            else if (d.EventText.StartsWith("NET Ports:"))
            {
                ConsoleWarnModule con = WarnModules.getConsoleWarnModule();
                if (con != null)
                {
                    Match m = Regex.Match(d.EventText, @"server \d+, client (\d+)");
                    if (m.Success)
                        con.ClientPort = Convert.ToInt32(m.Groups[1].Value);
                }
            }
        }

        void DebugMonitor_OnOutputDebugString(int pid, string text)
        {
            if (GameProcess == null || pid != GameProcess.Id)
                return;
            ConsoleEventItem i = new ConsoleEventItem(DateTime.Now, ConsoleEventItemType.None, text);
            ConsoleEvents.Add(i);
            if (!ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessDebugEvent), i))
                Trace.WriteLine("ERROR: Could not queue DebugEvent for procession! Too many Threads spawned?");
        }

        ~ESLReminder()
        {
            MainTimer.Change(0, Timeout.Infinite);
        }

        #region Properties
        public bool isRunning
        {
            get
            {
                return (GameProcess != null && !GameProcess.HasExited);
            }
        }

        private string m_Gamename;

        public string GameName
        {
            get
            {
                return m_Gamename;
            }
        }
        #endregion


        #region Settings

        private bool m_DisableDebugMonitor = false;

        public bool DisableDebugMonitor
        {
            get { return m_DisableDebugMonitor; }
            set { m_DisableDebugMonitor = value; }
        }
        public int AequitasWaitingTime = 5000;
        public TimeSpan OffsetBefore = new TimeSpan(0, 60, 0);
        public TimeSpan OffsetAfter = new TimeSpan(0, 120, 0);
        private string m_MatchLink = string.Empty;
        public string MatchLink
        {
            get
            {
                return m_MatchLink;
            }
        }
        private string m_Mod = string.Empty;
        public string Mod
        {
            get
            {
                return m_Mod;
            }
        }
        private int m_GameVersion = 1;
        public int GameVersion
        {
            get
            {
                return m_GameVersion;
            }
        }
        public bool WantsToExit = false;
        public bool DebugEnabled = true;
        public bool WarnOnNoDemo = false;
        public bool WarnAlways = true;
        public bool WarnOnTeamchange = true;
        public bool WarnOnNoStatus = true;
        public string LoginCookie = String.Empty;
        //public StringCollection WatchedFolders;
        public int ProcessAffinityAequitas;
        public int ProcessAffinityGame;
        public bool SetAffinityAequitas = false;
        public bool SetAffinityGame = false;
        public bool SetPrioGame = false;
        public bool OverwriteProtectionEnabled = true;
        public ulong FreeDiskspaceWarnThreshold = 120;
        public bool ParseConsoleAlways = true;
        public StringCollection MatchFilter = new StringCollection();
        private long m_MainTimerInterval = 5000;
        public VK InteractKey = VK.K;
        public long MainTimerInterval {
            get
            {
                return m_MainTimerInterval;
            }
            set
            {
                m_MainTimerInterval = value;
                MainTimer.Change(Timeout.Infinite, value);
            }
        }

        private long m_DemoTimerInterval = 5000;
        public long DemoTimerInterval
        {
            get
            {
                return m_DemoTimerInterval;
            }
            set
            {
                m_DemoTimerInterval = value;
                DemoTimer.Change(Timeout.Infinite, value);
            }
        }
        #endregion
    }
}
